
/*
 * Copyright (C) 2008-2009 Archie L. Cobbs. All rights reserved.
 *
 * $Id: AbstractSchemaUpdate.java 377 2010-03-11 20:50:18Z archie.cobbs $
 */

package org.dellroad.sidekar.schema.change;

import org.dellroad.sidekar.schema.SchemaModificationException;
import org.dellroad.sidekar.schema.model.EntityModel;
import org.dellroad.sidekar.schema.model.FieldModel;
import org.dellroad.sidekar.schema.model.SchemaModel;

/**
 * {@link SchemaChange} that adds a new field to some entity in the schema.
 */
public class AddFieldChange extends FieldChange {

    private final FieldModel fieldModel;

    /**
     * Constructor.
     *
     * @param entityName name of the entity to which the field should be added
     * @param fieldModel the new field's type
     * @throws IllegalArgumentException if {@code entityName} is not a legal entity name
     * @throws IllegalArgumentException if the field's name is not a legal field name
     * @throws IllegalArgumentException if {@code fieldModel} is null
     */
    public AddFieldChange(String entityName, FieldModel fieldModel) {
        super(entityName, AddFieldChange.getFieldName(fieldModel));
        this.fieldModel = fieldModel;
    }

    public FieldModel getFieldModel() {
        return this.fieldModel;
    }

    @Override
    public String getDescription() {
        return "add " + this.fieldModel + " to entity `" + this.getEntityName() + "'";
    }

    @Override
    public void checkValidFor(SchemaModel schemaModel) {
        super.checkValidFor(schemaModel);

        // Verify field name doesn't conflict with any existing field of ancestor or descendant
        final EntityModel entityModel = this.checkEntityExists(schemaModel, this.getEntityName());
        for (EntityModel otherEntityModel : schemaModel.getEntityModels().values()) {
            if (entityModel.isAncestorOf(otherEntityModel) || otherEntityModel.isAncestorOf(entityModel)) {
                if (otherEntityModel.getFieldModels().containsKey(this.fieldModel.getName())) {
                    throw new SchemaModificationException(this.getDescription(otherEntityModel, entityModel)
                      + " already contains a field named `" + this.fieldModel.getName() + "'");
                }
            }
        }
    }

    @Override
    public final void visit(SchemaChangeSwitch schemaChangeSwitch) {
        schemaChangeSwitch.caseAddFieldChange(this);
    }

    private static String getFieldName(FieldModel fieldModel) {
        if (fieldModel == null)
            throw new IllegalArgumentException("null fieldModel");
        return fieldModel.getName();
    }
}

